package gdf

import (
	"fmt"
	"gitee.com/liumou_site/logger"
	"io"
	"net/http"
)

// 根据长度与协程数量设置每个任务的长度
func (t *Thread) setRange(start, stop int64) {
	if t.SuppressRange {
		t.Request.Header.Del("Range")
		t.Request.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, stop))
	}
}

// waitMem 等待系统中有足够的内存可用。
// 该函数通过不断检查系统内存状态，直到系统内存满足预设条件。
// 参数:
//
//	l (int64): 需要的内存大小的下限。
//	f (int64): 内存因子，用于计算所需的内存大小。
//
// 返回:
//
//	无返回值。函数在满足内存条件时结束执行。
func waitMem(l, f int64) {
	for {
		// 检查是否有足够的内存。
		if IsEnoughMem(l, f) {
			// 如果有足够的内存，返回以继续执行其他操作。
			return
		} else {
			// 如果没有足够的内存，记录调试信息并继续等待。
			logger.Debug("wait mem")
		}
	}
}

// get函数负责发起HTTP请求并处理响应。
// 它使用http.DefaultClient发送请求，并根据响应状态和内容执行相应的逻辑。
// 如果响应状态不是成功状态，它会记录错误并设置Thread实例的Error字段。
// 如果一切正常，它会根据Thread实例的配置，要么将响应内容保存到磁盘，要么将其读入缓冲区。
func (t *Thread) get(req *http.Request) {
	// 在函数结束时通知等待组，表示任务完成。
	defer t.WaitGroup.Done()

	// 使用http.DefaultClient发送已准备好的HTTP请求，并处理可能发生的错误。
	// 它还确保在函数返回之前关闭响应体，以避免资源泄露。
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		logger.Error("Error:", err)
		t.Error = err
		return
	}

	// 使用defer确保HTTP响应体在函数返回前被正确关闭。
	// 这是必要的，因为不关闭响应体可能会导致资源泄漏，影响服务器性能。
	defer func(Body io.ReadCloser) {
		// 尝试关闭响应体
		err := Body.Close()
		// 如果关闭过程中发生错误，记录错误信息
		if err != nil {
			logger.Error(err)
		}
	}(resp.Body)

	// 检查HTTP响应状态码是否表示成功或部分内容。
	// 如果不是，记录错误并设置Thread实例的Error字段。
	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusPartialContent {
		logger.Error("Error: Status code", resp.StatusCode)
		t.Error = fmt.Errorf("error: Status code - %d", resp.StatusCode)
		return
	}

	// 计算文件大小（以MB为单位）。
	FileSizeMb := resp.ContentLength / 1024 / 1024

	// 如果启用了调试模式，打印有关下载文件的调试信息。
	if t.Debug {
		// 打印文件大小
		logger.Debug("Set File size:", FileSizeMb, "MB")
		// 打印文件类型
		//logger.Debug("File type -> " + resp.Header.Get("Content-Type"))
		// 打印文件长度
		logger.Debug("Set File length -> ", resp.ContentLength)
		// 打印分片
		logger.Debug("File range -> ", resp.Header.Get("Content-Range"))
	}

	// 根据配置决定是否将下载的内容保存到磁盘。
	if t.SaveToDisk {
		// 创建一个新的文件用于写入下载的内容
		t.Error = saveToDisk(t.DownloadFileName, resp)
		return
	} else {
		// 等待内存释放
		waitMem(FileSizeMb+t.MemFree, t.MemFree)
		// 将响应体内容读取到缓冲区中
		t.Error = buff(resp)
		return
	}
}
